// standard headers
#include <istream>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <map>
#include <cstdlib>

// boost headers
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem/path.hpp>

// components headers
#include <tree.h>
#include <matrix.h>
#include <tree_ops.h>
#include <portable_timer.h>
#include <progress_indicator.h>
#include <print_error.h>
#define DEBUG_LEVEL 6
#include <debug_func.h>
#include <stdlib.h>






using boost::format;
using boost::lexical_cast;
using boost::filesystem::path;
using std::vector;
using std::ostringstream;

using std::string;
using std::fill;
using std::ofstream;
using std::cout;
using std::cin;
using std::cerr;
using std::ifstream;
using std::map;
using std::pair;
using std::istream;
using std::max;
using std::min;
using namespace bcpp_matrix;
using namespace bcpp_tree_ops;









//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

//	main

//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

int main (int argc, char *argv[])
{
	// we use cout to print progress so flush per call
//	cout.setf(std::ios_base::unitbuf);

	std::ios::sync_with_stdio(false);

	string tree_name;
	bcpp_tree::t_tree species_tree;
	species_tree.set_sort_by_names(true);
	try
	{
		read_tree_from_stream(cin, species_tree, tree_name);
	}
	catch(std::exception& e)
	{
		std_print_error(string(e.what()) + "\nPlease supply a valid New Hampshire tree on the command line.\n");
	}

	cerr << "\tCalculating branch lengths...\n";
	// calculate branch lengths
	bcpp_tree_ops::do_calculate_branch_lengths branch_lengths(species_tree);

	// set node type to none
	std::vector<eNODETYPE>	node_types(species_tree.get_node_count(), eNONE);


	// print
	op_print_tree_elaborate print_tree_elaborate
								(species_tree,
								cerr,
								branch_lengths.lengths_to_leaves,
								branch_lengths.lengths_to_root,
								node_types,
								3	// precision
								);
	print_tree_elaborate.print();

	t_species_tree_map species_map(species_tree);


	//
	//	print out
	//
	//	but reverse everything for better legibility

	// use reverse indices
	vector<unsigned> indices;
	for (unsigned i = 0; i < species_map.cnt_duplications.size(); ++i)
		indices.push_back(i);
	std::reverse(indices.begin(),  indices.end());

	// labels in reverse
	op_set_labels_to_children_names do_set_labels(species_tree);
	vector<string> species_node_labels = species_tree.get_node_labels();
	std::reverse(species_node_labels.begin(),  species_node_labels.end());



	cerr << "\nParent lookup\n";
	t_dense_matrix<string> phylo_lookup_name(species_map.parent_species_UID.size());
	for (unsigned i = 0, sz = species_map.parent_species_UID.size(); i != sz; ++i)
		for (unsigned j = 0; j != sz; ++j)
			phylo_lookup_name[i][j] = species_tree.get_node_labels()[species_map.parent_species_UID[i][j]];
	t_dense_matrix<string> phylo_lookup_name_rev(phylo_lookup_name.size());
	phylo_lookup_name.sub_matrix(indices, phylo_lookup_name_rev);
	dump_to_stream(cerr,  phylo_lookup_name_rev, species_node_labels);


	cerr << "\nMapping function (Count missing taxa)\n";
	t_dense_matrix<unsigned> cnt_missing_taxa_rev(species_map.cnt_missing_taxa.size());
	species_map.cnt_missing_taxa.sub_matrix(indices, cnt_missing_taxa_rev);
	dump_to_stream(cerr,  cnt_missing_taxa_rev, species_node_labels);


	cerr << "\nMapping function (Count duplications)\n";
	t_dense_matrix<unsigned> cnt_duplications_rev(species_map.cnt_duplications.size());
	species_map.cnt_duplications.sub_matrix(indices, cnt_duplications_rev);
	dump_to_stream(cerr,  cnt_duplications_rev, species_node_labels);

	cerr << "\n\tAll finished!!\n\n";

	return 0;
}




